package com.mybatis.study.session;

import java.io.BufferedInputStream;
import java.io.BufferedOutputStream;
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.net.URL;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;
import java.util.stream.Collector;
import java.util.stream.Collectors;

import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import com.mybatis.study.config.Configuration;
import com.mybatis.study.config.MapperStatement;
import com.mybatis.study.model.FieldAndType;
import com.mybatis.study.session.impl.DefaultSqlSession;

//1初始化加载Configuration配置文件信息
//2生成sqlsession 


//疑问疑问 getResourceAsStream方法的差异
//this.getClass().getClassLoader().getResource(MAPPER_CONFIG_LOCATION);
public class SqlSessionFactory {

	private final Configuration configuration = new Configuration();

	public static final String DB_CONFIG_FILE = "db.properties";

	public static final String MAPPER_CONFIG_LOCATION = "mappers";

	public static final String MAPPER_CONFIG_LOCATION_HH = "/com/mybatis/study/mapperss";

	public SqlSessionFactory() {
		loadDbInfo();
		loadMapperInfo();
	}

	public SqlSession getSession() {
		return new DefaultSqlSession(configuration);
	}

	private void loadDbInfo() {
		InputStream dbInfo = SqlSessionFactory.class.getClassLoader().getResourceAsStream(DB_CONFIG_FILE);
		Properties p = new Properties();
		try {
			p.load(dbInfo);
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		configuration.setJdbcDriver(p.get("jdbc.driver").toString());
		configuration.setJdbcPassword(p.get("jdbc.password").toString());
		configuration.setJdbcUsername(p.get("jdbc.username").toString());
		configuration.setJdbcUrl(p.get("jdbc.url").toString());
	}

	private void loadMapperInfo() {
		URL resource = null;
		URL resource2 = null;
		resource = this.getClass().getClassLoader().getResource(MAPPER_CONFIG_LOCATION);
		resource2 = SqlSessionFactory.class.getResource(MAPPER_CONFIG_LOCATION_HH);
//		InputStream inputSteam = SqlSessionFactory.class.getClassLoader().getResourceAsStream(MAPPER_CONFIG_LOCATION);
//		InputStream inputSteam2 = SqlSessionFactory.class.getClassLoader()
//				.getResourceAsStream(MAPPER_CONFIG_LOCATION_HH);
		// sysInputSteam(inputSteam);
		// sysInputSteam(inputSteam2);
		File mappers = new File(resource.getFile()); // 获取指定文件夹
		if (mappers.isDirectory()) {
			File[] files = mappers.listFiles();
			for (File fileItem : files) {
				loadMapperInfo(fileItem);
			}
		}
	}

//	private void sysInputSteam(File files) {
//		try {
//			File file = new File("D:\\worksplaces\\nda\\mybatis-simple\\src\\main\\resources\\mappers\\xx.txt");
//			FileOutputStream fileOutSteam=new FileOutputStream(file); 
//			FileInputStream fileInputStream=new FileInputStream(files);
//	        int hasInput=0;
//	        while((hasInput = fileInputStream.read())!=-1){
//	        	               System.out.print((char)hasInput);
//	        	               fileOutSteam.write(hasInput);
//	        }
//		}catch (Exception e) {
//			// TODO: handle exception
//			e.printStackTrace();
//		}
//	}

	private void loadMapperInfo(File file) {
		SAXReader reader = new SAXReader();
		Document document = null;
		try {
			//sysInputSteam(file);
			document = reader.read(file);
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		Element root = document.getRootElement();
		String namespace = root.attribute("namespace").getData().toString();
		List<Element> selects = root.elements("select");
		List<Element> resultMaps=root.elements("resultMap");
		Map<String, Element> reMap=new HashMap<String, Element>();
		for (Element element : resultMaps) {
			System.out.println(element.attribute("id").getData().toString());
			reMap.put(element.attribute("id").getData().toString(), element);
		}
		//不清楚为什么
		//Map<String, Element> reMap=resultMap.stream().collect(Collectors.toMap(Element -> attribute("id").getData().toString(), account -> account));
		
		for (Element element : selects) {
			MapperStatement statement = new MapperStatement();
			String id = element.attribute("id").getData().toString();
			String resultMap = element.attribute("resultMap").getData().toString();
			String resultType="";
			if(null!=resultMap && resultMap!="") {
				resultType=packResultMap(resultMap, reMap, statement);
			}else {
				resultType=element.attribute("resultType").getData().toString();
			}
			String sql = element.getData().toString();
			String sourceId = namespace + "." + id;
			statement.setNamespace(namespace);
			statement.setResultType(resultType);
			statement.setSourceId(sourceId);
			statement.setSql(sql);
			configuration.getMapperStatementMap().put(sourceId, statement);
		}
	}

	private String packResultMap(String resultMap,Map<String, Element> reMap,MapperStatement statement) {
		if(reMap.containsKey(resultMap)) {
			List<Element> results=reMap.get(resultMap).elements("result");
			    for (Element element3 : results) {
			    	FieldAndType type=new FieldAndType(element3.attribute("column").getData().toString(), element3.attribute("jdbcType").getData().toString());
				    statement.getFieldToMap().put(element3.attribute("property").getData().toString(),type);
				}
		    if(null!=reMap.get(resultMap).attribute("extends").getData().toString() && reMap.get(resultMap).attribute("extends").getData().toString()!="") {
				List<Element> resultss=reMap.get(reMap.get(resultMap).attribute("extends").getData().toString()).elements("result");
				for (Element element3 : resultss) {
					FieldAndType type=new FieldAndType(element3.attribute("column").getData().toString(), element3.attribute("jdbcType").getData().toString());
					statement.getFieldToMap().put(element3.attribute("property").getData().toString(),type);
				}
			}
		    return reMap.get(resultMap).attribute("type").getData().toString();
		}else {
			return null;
		}
	}
}
